using Core;
using UnityEngine;

namespace Modules.Viewport
{
    public class ViewportController : GameSubsystem
    {
        public bool control = true;

        // 接触半径
        public float proximityRadius = 0.5f;

        [Space]
        // 移动、升降和旋转的速度
        public float moveSpeed = 1f; // 移动速度

        public float heightSpeed = 1f; // 升降速度
        public float rotationSpeed = 5f; // 旋转速度

        // 阻尼参数
        public float moveSmoothTime = 0.1f; // 移动平滑时间
        public float heightSmoothTime = 0.1f; // 升降平滑时间
        public float rotationSmoothTime = 0.1f; // 旋转平滑时间

        [Space] public LayerMask layerMask = 1 << 0;

        private Vector3 _currentMoveDirection; // 当前移动方向和量
        private Vector3 _targetMoveDirection; // 目标移动方向和量
        private Vector3 _moveVelocity; // 移动速度缓存

        private Vector3 _currentHeightChange; // 当前高度变化量
        private Vector3 _targetHeightChange; // 目标高度变化量
        private Vector3 _heightVelocity; // 高度速度缓存

        private Vector3 _currentRotationChange; // 当前旋转变化量
        private Vector3 _targetRotationChange; // 目标旋转变化量
        private Vector3 _rotationVelocity; // 旋转速度缓存

        private ViewportInputSystem _inputSystem;

        private Transform _mainCamera;

        protected override void Awake()
        {
            base.Awake();
            _mainCamera = Camera.main?.transform;
            _inputSystem = new ViewportInputSystem(); // 初始化输入系统
        }

        private void OnEnable()
        {
            _inputSystem.Enable(); // 启用输入系统
        }

        private void OnDisable()
        {
            _inputSystem.Disable(); // 禁用输入系统
        }

        private void LateUpdate()
        {
            if (!IsControl())
                return; // 如果角色不受控制，则不进行任何操作
            UpdateMovement(); // 更新角色的移动
            UpdateHeight(); // 更新角色的高度
            UpdateRotation(); // 更新角色的旋转
        }

        /// <summary>
        /// 处理角色的移动逻辑，根据输入值和环境判断角色的移动方向和速度。
        /// </summary>
        private void UpdateMovement()
        {
            Vector2 inputValue = _inputSystem.Custom.Move.ReadValue<Vector2>();

            // 定义方向向量
            Vector3 forward = transform.forward;
            forward.y = 0;
            forward.Normalize();

            Vector3 right = transform.right; // 定义右侧方向

            // 按下移动键时进行移动
            _targetMoveDirection = Vector3.zero; // 重置目标速度

            if (inputValue.y > 0 && IsDirectionWalkable(forward)) // 向前移动
            {
                _targetMoveDirection += forward * moveSpeed;
            }
            else if (inputValue.y < 0 && IsDirectionWalkable(-forward)) // 向后移动
            {
                _targetMoveDirection -= forward * moveSpeed; // 向后移动
            }

            if (inputValue.x < 0 && IsDirectionWalkable(-right)) // 向左移动
            {
                _targetMoveDirection -= right * moveSpeed; // 使用 -right 向左移动
            }
            else if (inputValue.x > 0 && IsDirectionWalkable(right)) // 向右移动
            {
                _targetMoveDirection += right * moveSpeed; // 向右移动
            }

            // 使用 SmoothDamp 实现阻尼效果
            _currentMoveDirection = Vector3.SmoothDamp(_currentMoveDirection, _targetMoveDirection, ref _moveVelocity, moveSmoothTime);

            // 更新位置
            transform.position += _currentMoveDirection * Time.deltaTime;
        }

        /// <summary>
        /// 处理角色的旋转逻辑，根据输入值计算角色的旋转角度并应用阻尼效果。
        /// </summary>
        private void UpdateRotation()
        {
            Vector2 lookInput = _inputSystem.Custom.Look.ReadValue<Vector2>();

            // 计算目标旋转
            _targetRotationChange = new Vector3(-lookInput.y * rotationSpeed, lookInput.x * rotationSpeed, 0) * Time.deltaTime;

            // 使用 SmoothDamp 实现阻尼效果
            _currentRotationChange = Vector3.SmoothDamp(_currentRotationChange, _targetRotationChange, ref _rotationVelocity, rotationSmoothTime);

            // 更新角色的旋转，并将当前位置的旋转角度转换为欧拉角
            Vector3 newRotation = transform.localEulerAngles + _currentRotationChange;

            // 限制 X 轴的旋转范围
            if (newRotation.x >= 180)
                newRotation.x -= 360;
            if (newRotation.x < -180)
                newRotation.x += 360;
            newRotation.x = Mathf.Clamp(newRotation.x, -89.5f, 89.5f);

            // 更新最终旋转
            transform.localEulerAngles = newRotation;
        }

        /// <summary>
        /// 处理角色的高度变化逻辑，根据输入值改变角色的高度，并应用阻尼效果。
        /// </summary>
        private void UpdateHeight()
        {
            float heightInput = _inputSystem.Custom.Height.ReadValue<float>();
            Vector3 upwardMovement = Vector3.up * (heightInput * heightSpeed * Time.deltaTime);

            // 计算目标高度移动
            _targetHeightChange = Vector3.zero; // 重置目标高度变化量

            // 判断上下移动的方向
            if (heightInput > 0 && IsDirectionWalkable(Vector3.up)) // 向上移动
            {
                _targetHeightChange = upwardMovement; // 目标向上移动
            }
            else if (heightInput < 0 && IsDirectionWalkable(Vector3.down)) // 向下移动
            {
                _targetHeightChange = upwardMovement; // 目标向下移动
            }

            // 使用 SmoothDamp 实现阻尼效果
            _currentHeightChange = Vector3.SmoothDamp(_currentHeightChange, _targetHeightChange, ref _heightVelocity, heightSmoothTime);

            // 更新位置
            transform.position += _currentHeightChange;
        }

        /// <summary>
        /// 检查角色在给定方向上是否可以移动，避免与障碍物发生碰撞。
        /// </summary>
        /// <param name="direction">要检查的移动方向。</param>
        /// <returns>如果可以在指定方向上移动，则返回 true；否则返回 false。</returns>
        private bool IsDirectionWalkable(Vector3 direction)
        {
            return !Physics.CheckSphere(transform.position + direction * proximityRadius, proximityRadius, layerMask);
        }

        /// <summary>
        /// 设置摄像机的位置和旋转。
        /// </summary>
        public void SetCameraPos(Vector3 position, Vector3 rotation)
        {
            transform.position = position;
            transform.rotation = Quaternion.Euler(rotation);
        }

        /// <summary>
        /// 初始化摄像机状态，立即消除阻尼效果。
        /// </summary>
        public void Init()
        {
            // 立即同步移动方向
            _currentMoveDirection = _targetMoveDirection;
            _moveVelocity = Vector3.zero;

            // 立即同步高度变化
            _currentHeightChange = _targetHeightChange;
            _heightVelocity = Vector3.zero;

            // 立即同步旋转变化
            _currentRotationChange = _targetRotationChange;
            _rotationVelocity = Vector3.zero;

            _mainCamera.parent = transform;
            _mainCamera.localPosition = Vector3.zero;
            _mainCamera.localEulerAngles = Vector3.zero;
        }

        private bool IsControl()
        {
            if (!control)
                return false;
            if (_mainCamera.parent != transform)
                return false;
            return true;
        }
    }
}